Asset Modules与资源文件处理
file-loader
在 JS 中,我们使用 import
引入的图片资源时,在 webpack 打包的时候需要借助 file-loader
来处理。file-loader
的作用就是帮助我们处理 import/require()
引入的文件资源,并且打包后会将它们一起放到打包文件中去。
另外,还有一个场景就是在样式文件中使用 background: url(xxx)
引入某个图片资源作为背景,file-loader
也可以对其处理。
首先安装 file-loader
。
$ npm i file-loader -D
然后在 webpack.config.js
添加如下配置。
{
test: /\.(png|jpe?g|gif|svg)$/,
use: [
{
loader: "file-loader",
options: {
name: "img/[name].[hash:6].[ext]",
// outputPath: "img" // 可以这样用但是不建议
}
}
]
},
webpack 在打包过程中,如果发现某个 js 文件导入了一个图片资源文件,那么就会将该图片打包到 output
根目录下的 img
目录中。
这里的 [name].[hash:6].[ext]
是占位符,[name]
表示资源文件名,[hash:6]
表示取 6 位的哈希值,[ext]
表示文件的后缀名。
下面是几个常用的占位符。
占位符 | 说明 |
---|---|
[ext] | 被处理文件的扩展名 |
[name] | 被处理文件的文件名 |
[hash] | 被处理文件的内容,由 md4 算法处理,生成了 128 位的 hash 值 ( 32 个十六进制数) |
[contentHash] | 对于 file-loader 来说和 [hash] 相同,但是在 webpack 的其他一些地方不一样,后面会讲到 |
[hash:\<length>] | 截取指定长度哈希值 |
[path] | 被处理文件相对于 webpack 配置文件的路径 |
important
如果我们不给 file-loader
传递 name
参数,那么在默认情况下打包后的图片资源文件名类似这个样子 615a7b44840a5feef178068b86dabb7d.png
,底层使用了 md4 摘要算法,将资源中的内容提取出来转换成了 128 bit 位的哈希值,然后再转为十六进制,最终就成为了这样的文件名。
url-loader
url-loader
和 file-loader
的工作方式相似,但是 url-loader
对于较小的文件,可以将其转成 base64 和 uri。
首先安装 url-loader
。
$ npm i url-loader -D
然后在 webpack.config.js
添加如下配置。
{
test: /\.(png|jpe?g|gif|svg)$/,
use: [
{
loader: "url-loader",
options: {
name: "img/[name].[hash:6].[ext]",
limit: 100 * 1024 // 100KB
}
}
]
}
可以向 url-loader
传递一个 limit
参数,这里以 100KB 为分界点,小于 100KB 的图片使用 base64,大于 100KB 的图片直接单独放一个文件夹。
图片存储优化
- 对于较大的图片我们应该存放到单独的一个文件夹里面,可以先让页面中显示一部分
- 对于较小的图片可以直接 base64,放到 js 文件中,以此来减少 http 请求次数
raw-loader
使用该 loader
可以允许导入一个外部文件,将其内容作为字符串使用。
详情参考 raw-loader。
Asset Modules
在 webpack5 之前加载某些资源的时候需要使用一些 loader,比如:raw-loader
、url-loader
、file-loader
,从 webpack5 开始,我们可以直接使用 资源模块类型 ( asset module type ),来替代这些 loader
。
资源模块类型 | 说明 |
---|---|
asset/resource | 作用可以类比于 file-loader |
asset/inline | 作用可以类比于 url-loader ,但只能生成内联资源(data uri) |
asset | 综合上面两种类型的作用 |
asset/source | 导出资源的源代码,这个不常用 |
important
在 webpack5 之后,不再推荐使用其他 loader
来处理图片、字体等资源文件了,比如你使用 file-loader
来处理图片资源,很可能出现一些奇怪的问题。
asset/resource
作用和 file-loader
类似,无论是直接通过 import/require
导入图片资源,还是设置 background: url(xxx)
,webpack 在打包过程中都会将资源打包单独的目录下。
你需要在 webpack.config.js
中添加如下配置。
{
test: /\.(png|jpe?g|gif|svg)$/,
type: "asset/resource",
generator: {
filename: "img/[name].[hash:6][ext]"
}
}
asset/inline
作用和 url-loader
类似,但是需要注意的是无法设置 limit
,无论多大的图片资源,最终都会被 base64,以 data uri 的方式进行内联。
你需要在 webpack.config.js
中添加如下配置。
{
test: /\.(png|jpe?g|gif|svg)$/,
type: "asset/inline"
}
asset
综合了 asset/resource
和 asset/inline
的效果,可以设置一个分界值,如果资源大小超过这个分界值,那么就将其打包到单独的目录,否则就以内联(data uri)的形式引入。
你需要在 webpack.config.js
中添加如下配置。
{
test: /\.(png|jpe?g|gif|svg)$/,
type: "asset",
generator: {
filename: "img/[name].[hash:6][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 100 * 1024 // 超过 100KB 则单独打包出来
}
}
}
asset/source
可以在项目中导入某个文件,将其内容作为字符串使用,作用和 raw-loader
类似。
比如,你在 webpack.config.js
中添加了如下配置。
{
test: /\.txt/,
type: "asset/source"
}
那么你就可以在 js 中直接导入一个 txt 文本文件,将其内容作为字符串使用。
import text from "./hello.txt";
const s = text; // 文件中的内容